home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1997 January: Mac OS SDK / Dev.CD Jan 97 SDK2.toast / Development Kits (Disc 2) / ScriptX / Documentation / Code Examples from Docs / compguid / evntsdev / eventdsp.sx next >
Encoding:
Text File  |  1996-05-21  |  6.8 KB  |  188 lines  |  [TEXT/ttxt]

  1. -- <<<-
  2.  
  3. -- eventdsp.sx
  4. -- Event Dispatcher example
  5. -- by Howard Metzenberg
  6. -- have yourself a rilly big one
  7. -- from "Events and Input Devices" chapter of
  8. -- ScriptX Components Guide
  9.  
  10. module EventTest2 uses ScriptX end
  11. in module EventTest2
  12.  
  13. class EventDispatcher (RootObject)
  14. instance variables
  15.     interestList -- KeyedLinkedList
  16.     thread -- a thread for responding to user actions
  17.     eventQueue -- use this queue to receive events
  18. instance methods
  19.     method init self #rest args -> (
  20.         self.interestList := new KeyedLinkedList
  21.         -- note that the event queue replaces the condition
  22.         -- in the Dispatcher class, in the Threads chapter
  23.         -- the queue itself acts as a gate
  24.         self.eventQueue := new EventQueue thread:(self.thread) 
  25.         self.thread := new Thread func:dThreadFn arg:self priority:@system
  26.         apply nextMethod self args
  27.     )
  28. end -- (Dispatcher class definition)
  29.  
  30. method addInterest self {class EventDispatcher} eventClass func data -> (
  31.     -- check that func is a kind of function
  32.     if isAKindOf func AbstractFunction then (
  33.         -- check that eventClass is a class, and that it inherits from Event
  34.         if isAKindOf eventClass RootClass and isSub eventClass Event then (
  35.             local newInterest
  36.             newInterest := New eventClass
  37.             newInterest.authorData := func
  38.             newInterest.eventReceiver := self.eventQueue
  39.             newInterest.priority := 2
  40.             addEventInterest newInterest
  41.             add self.interestList newInterest data
  42.         ) else (
  43.             format debug "Second argument must be an event class!/n" \
  44.                     undefined @normal
  45.         )
  46.     ) else (
  47.         format debug "Third argument must be a function or generic!/n" \ 
  48.                     undefined @normal
  49.     )
  50. )
  51. method removeInterest self {class EventDispatcher} eventClass -> (
  52.     -- check that eventClass is currently defined 
  53.     -- and that the event dispatcher has as an interest in it
  54.     if isAKindOf eventClass RootClass and isSub eventClass Event then (
  55.         local i := iterate self.interestList
  56.         repeat while (next i) do (
  57.             if (getClass i.key = eventClass) do (
  58.                 removeEventInterest i.key
  59.                 excise i -- this deletes it from the collection
  60.                 exit -- remove only the first occurrence
  61.             )
  62.         )
  63.     ) else (
  64.         format debug "Second argument must be an event class!/n" \
  65.                 undefined @normal
  66.     )
  67. )
  68.  
  69. function dThreadFn dispatcher -> (
  70.     local myEvent := undefined
  71.     local data := undefined
  72.     repeat while (myEvent := read dispatcher.eventQueue) do (
  73.         -- figure out how the event was delivered and
  74.         -- get the data that goes with the associated interest
  75.         if isAKindOf (myEvent.matchedInterest) Event then (
  76.             -- must have been delivered by signal method
  77.             accept myEvent
  78.             data := dispatcher.interestList[myEvent.matchedInterest]
  79.             -- call the function with event and data as arguments
  80.             (myEvent.matchedInterest.authorData) myEvent data
  81.         ) else (
  82.             -- event could not have been signaled, so see if broadcast
  83.             -- if matchedInterest is undefined, it must have been delivered
  84.             -- using the sendToQueue method
  85.             if myEvent.matchedInterest <> undefined then (
  86.                 -- matchedInterest can have one of three values
  87.                 -- it can be an event, an array of events, or undefined
  88.                 -- it must have been delivered by broadcast method
  89.                 -- get an iterator for the array of matching interests
  90.                 -- this next line creates a sequence iterator i
  91.                 local i := iterate (myEvent.matchedInterest)
  92.                 local myClass := getClass myEvent
  93.                 -- now iterate through the matchedInterest collection
  94.                 repeat while (next i) do (
  95.                     -- make sure it is one of our own interests
  96.                     -- see if the matching interest is in our own list
  97.                     -- if not, then go on to the next matched interest
  98.                     if getOne dispatcher.interestList (i.value) = empty do (
  99.                         continue -- so skip and go on to the next
  100.                     )
  101.                     data := dispatcher.interestList[i.value]
  102.                     -- call the function with event and data as arguments
  103.                     (i.value.authorData) myEvent data
  104.                     -- excise it in case there were other event interests
  105.                     -- in our own private list.
  106.                     -- this only removes it from the collection of interests
  107.                     -- that matched the current event. It is still 
  108.                     -- registered as an interest to receive future events.
  109.                     excise i 
  110.                     exit
  111.                 ) -- end repeat
  112.             ) else (
  113.                 -- must have been delivered by sendToQueue method
  114.                 format debug "not interested in this event!\n" undefined @normal
  115.                 myEvent := undefined
  116.                 continue -- ignore this event, go back and wait for another
  117.             )
  118.         )
  119.         -- reset it so the thread will block until the next event comes along
  120.         myEvent := undefined
  121.     )
  122. )
  123.  
  124. -- now create three new classes of events to test it with
  125. class GrokEvent (Event) end
  126. class VoodooEvent (Event) end
  127. class EarthQuakeEvent (Event) end
  128. -- create an instance of EventDispatcher
  129. global gDispatcher := new EventDispatcher 
  130. -- the init method on Dispatcher automatically creates a thread
  131. -- define some functions that will be called
  132. global fn func1 myEvent x -> (
  133.     format debug "Function 1 just got a %* event " (getClass myEvent) @normal
  134.     format debug "and its argument is %*.\n" x @normal
  135. )
  136. global fn func2 myEvent x -> (
  137.     format debug "Function 2 just got a %* event " (getClass myEvent) @normal
  138.     format debug "and its argument is %*.\n" x @normal
  139. )
  140. global fn func3 myEvent x -> (
  141.     format debug "Function 3 just got a %* event " (getClass myEvent) @normal
  142.     format debug "and its argument is %*.\n" x @normal
  143. )
  144. -- now create some interests in the three kinds of events
  145. -- add them to the interest list, with their associated functions and arguments
  146. addInterest gDispatcher GrokEvent func1 "moof"
  147. addInterest gDispatcher VoodooEvent func2 "foo"
  148. addInterest gDispatcher EarthQuakeEvent func3 "7.1"
  149. addInterest gDispatcher EarthQuakeEvent func1 "8.7"
  150.  
  151. -- create some events and send them
  152. global myGrokEvent := new GrokEvent
  153. global myVoodooEvent := new VoodooEvent
  154. global prittyBigOne := new EarthQuakeEvent
  155. global rillyBigOne := new EarthQuakeEvent
  156. signal myGrokEvent true
  157. signal myVoodooEvent true
  158. broadcast prittyBigOne
  159. broadcast rillyBigOne
  160.  
  161. -- create an event receiver and associated event interests
  162. function eventEater event interest data -> (
  163.     format debug "eventEater just received an event. \n" undefined @normal
  164.     format debug "authorData: %* \n" event @normal
  165.     format debug "Interest: %* \n" interest @normal
  166.     format debug "Event: %* \n" data @normal
  167. )
  168. global shakeInterest := new EarthQuakeEvent
  169. shakeInterest.authorData := "No function at all!"
  170. shakeInterest.priority := 1 -- this one has higher priority
  171. shakeInterest.eventReceiver := eventEater
  172. addEventInterest shakeInterest
  173. global rattleInterest := new EarthQuakeEvent
  174. rattleInterest.authorData := "Definitely not a function!"
  175. rattleInterest.priority := 3 -- this one has lower priority
  176. rattleInterest.eventReceiver := eventEater
  177. addEventInterest rattleInterest
  178.  
  179. -- now create some more events and signal them
  180. global mightyOne := new EarthQuakeEvent
  181. global awesomeOne := new EarthQuakeEvent
  182. global giantOne := new EarthQuakeEvent
  183. broadcast mightyOne
  184. broadcast awesomeOne
  185. sendToQueue giantOne gDispatcher.eventQueue
  186.  
  187. -- >>>
  188.